﻿#define DEBUG

using System;
using System.Configuration;
using System.ServiceProcess;
using System.ServiceModel;
using System.Diagnostics;
using System.Collections.Generic;
using System.ServiceModel.Dispatcher;

namespace StockholmsStad.WindowsService
{
    /// <summary>
    /// 
    /// </summary>
    public class StockholmsStadWcfService : ServiceBase, IErrorHandler
    {
        private const string LOGGING_SOURCE = "Parvis Services";
        private const string LOGNAME = "Application";

        private readonly List<ServiceHost> hosts = new List<ServiceHost>();
        private EventLog eventLog;

        private ServiceHost winServiceHost;
        private ServiceHost webServiceHost;

        /// <summary>
        /// Default konstruktor.
        /// </summary>
        public StockholmsStadWcfService()
        {           
            InitializeComponent();

            InitializeLogging();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="args"></param>
        public static void Main(string[] args)
        {
            var service = new StockholmsStadWcfService();

            if (Environment.UserInteractive)
            {
                service.OnStart(args);
                Console.WriteLine("Press any key to stop program");
                Console.Read();
                service.OnStop();
            }
            else
            {
                Run(service);
            }
        }

        private void InitializeLogging()
        {
            // Initera eventLog-referensen
            if (!EventLog.SourceExists(LOGGING_SOURCE))
            {
                EventLog.CreateEventSource(LOGGING_SOURCE, LOGNAME);
            }

            eventLog.Source = LOGGING_SOURCE;
            eventLog.Log = LOGNAME;
        }

        /// starta windowstjänsten
        protected override void OnStart(string[] args)
        {
            // Hämta listan med tjänster som ska startas
            var servicesSection = ConfigurationManager.GetSection("serviceSettings") as ServicesConfigurationSection;

            if (servicesSection == null)
            {
                var error = "Misslyckades att ladda 'serviceSettings' från konfigurationsfilen.";
                eventLog.WriteEntry(error, EventLogEntryType.Error);
                throw new ConfigurationErrorsException(error);
            }

            try
            {
                foreach (ServiceConfigurationElement serviceElement in servicesSection.Services)
                {
                    // Hämta tjänstens typ
                    var serviceType = Type.GetType(serviceElement.TypeName, true, true);

                    if (serviceType == null)
                    {
                        var error = string.Format("Misslyckades att hämta servicetypen ({0}) från konfigurationsfilen",
                                                  serviceElement.TypeName);
                        eventLog.WriteEntry(error, EventLogEntryType.Error);
                        throw new TypeLoadException(error);
                    }

                    // Öppnar värden
#if DEBUG 
                    Console.WriteLine(string.Format("Försöker starta tjänsten: {0}", serviceElement.Name));
#endif
                    OpenHost(serviceType, serviceElement.Name);
                }

            }
            catch (Exception e)
            {
#if DEBUG
                Console.WriteLine(string.Format("Kunde inte starta tjänsten. Detaljer: {0}", e.Message));
#endif
                 eventLog.WriteEntry(string.Format("Kunde inte starta tjänsten. Detaljer: {0}", e.Message), EventLogEntryType.Error);
                return;
            }
        }

        /// <summary>
        /// Öppnar en värd med den aktulla typen. 
        /// </summary>
        /// <param name="hostType">The host type.</param>
        /// <param name="name">Namnet på WCF tjänsten som startas. </param>
        private void OpenHost(Type hostType, string name)
        {
            var host = new ServiceHost(hostType);
            OpenHost(host, name);
        }

        /// <summary>
        /// Öppnar den aktuella värden
        /// </summary>
        /// <param name="host">Värden som ska öppnas. </param>
        /// <param name="name">Namnet på WCF tjänsten som startas. </param>
        private void OpenHost(ServiceHost host, string name)
        {
            host.Open();
            hosts.Add(host);

#if DEBUG
            Console.WriteLine(string.Format("Startar tjänsten: {0}", name));
#endif

            eventLog.WriteEntry(string.Format("Startar tjänsten: {0}", name));
        }

        /// stoppa windowstjänsten
        protected override void OnStop()
        {
            if (winServiceHost != null)
            {
                winServiceHost.Close();
                winServiceHost = null;
            }

            if (webServiceHost != null)
            {
                webServiceHost.Close();
                webServiceHost = null;
            }
        }

        private void InitializeComponent()
        {
            eventLog = new EventLog();
            ((System.ComponentModel.ISupportInitialize)(eventLog)).BeginInit();
            // 
            // ServiceTest
            // 
            ((System.ComponentModel.ISupportInitialize)(eventLog)).EndInit();

        }

        #region IErrorHandler Members

        /// <summary>
        /// 
        /// </summary>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool HandleError(Exception error)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="error"></param>
        /// <param name="version"></param>
        /// <param name="fault"></param>
        public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
